package com.zdxlz.fcmp.upms.api.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdxlz.fcmp.common.core.exception.BizException;
import com.zdxlz.fcmp.common.mybatis.enums.MenuTypeEnum;
import com.zdxlz.fcmp.upms.api.dto.SystemMenuDto;
import com.zdxlz.fcmp.upms.api.entity.SystemMenu;
import com.zdxlz.fcmp.upms.api.entity.SystemRoleMenu;
import com.zdxlz.fcmp.upms.api.mapper.SystemMenuMapper;
import com.zdxlz.fcmp.upms.api.mapper.SystemRoleMenuMapper;
import com.zdxlz.fcmp.upms.api.service.ISystemMenuService;
import com.zdxlz.fcmp.upms.api.vo.Meta;
import com.zdxlz.fcmp.upms.api.vo.SystemMenuListVo;
import com.zdxlz.fcmp.upms.api.vo.SystemMenuTreeVo;
import com.zdxlz.fcmp.upms.api.vo.SystemMenuVo;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.zdxlz.fcmp.common.core.constant.CommonConstants.STRING_ZERO;
import static com.zdxlz.fcmp.common.core.constant.enums.ResCode.*;

/**
 * 菜单信息表(SystemMenu)表服务实现类
 *
 * @author aman
 * @since 2025-01-15 16:59:00
 */
@Service
public class SystemMenuServiceImpl extends ServiceImpl<SystemMenuMapper, SystemMenu> implements ISystemMenuService {

    @Resource
    private SystemMenuMapper systemMenuMapper;

    @Resource
    private SystemRoleMenuMapper systemRoleMenuMapper;

    /**
     * @Description：List<SystemMenu>【转为】List<SystemMenuVo>
     * @Author：aman
     * @Date：2025/1/17 11:15
     */
    public static List<SystemMenuVo> convertSysResourceToMenuVO(List<SystemMenu> resources) {
        List<SystemMenuVo> menuVOList = new ArrayList<>();
        resources.forEach(item -> {
            SystemMenuVo systemMenuVo = new SystemMenuVo();
            BeanUtil.copyProperties(item, systemMenuVo, false);
            menuVOList.add(systemMenuVo);
        });
        return menuVOList;
    }

    /**
     * @Description：List<SystemMenuVo>【转为】List<SystemMenuTreeVo>，最终转为父子结构的集合数据
     * @Author：aman
     * @Date：2025/1/17 11:17
     */
    public static List<SystemMenuTreeVo> buildSystemMenuTreeVo(List<SystemMenuVo> sysMenuRespList) {
        Map<String, SystemMenuVo> map = new HashMap<>();
        // 先将所有资源按照父节点ID进行分组
        for (SystemMenuVo menuVo : sysMenuRespList) {
            menuVo.setChildren(new ArrayList<>()); // 初始化children属性
            map.put(String.valueOf(menuVo.getId()), menuVo);
            // 如果是根节点则直接加入结果列表
            if (STRING_ZERO.equals(menuVo.getParentId())) {
                map.put(String.valueOf(menuVo.getId()), menuVo);
            } else {
                // 如果不是根节点，则加入父节点的 children 列表
                SystemMenuVo parent = map.get(menuVo.getParentId());
                if (parent != null) {
                    parent.getChildren().add(buildMenuTree(menuVo));
                }
            }
        }
        // 获取所有根节点并返回
        List<SystemMenuTreeVo> result = new ArrayList<>();
        for (SystemMenuVo menuVo : sysMenuRespList) {
            if (STRING_ZERO.equals(menuVo.getParentId())) {
                SystemMenuTreeVo systemMenuTreeVo = buildMenuTree(menuVo);
                result.add(systemMenuTreeVo);
            }
        }
        return result;
    }

    /**
     * @Description：List<SystemMenu>【转为】List<SystemMenuListVo>
     * @Author：aman
     * @Date：2025/1/17 11:16
     */
    public static List<SystemMenuListVo> convertSysResourceToMenuListVO(List<SystemMenu> systemMenus) {
        List<SystemMenuListVo> menuVOList = new ArrayList<>();
        systemMenus.forEach(item -> {
            String meta = item.getMeta();
            SystemMenuListVo systemMenuVo = new SystemMenuListVo();
            BeanUtil.copyProperties(item, systemMenuVo, "meta");
            systemMenuVo.setMeta(JSON.to(Meta.class, meta));
            systemMenuVo.setMenuType(Integer.toString(item.getMenuType().getCode()));
            menuVOList.add(systemMenuVo);
        });
        return menuVOList;
    }

    /**
     * @Description：构建【SystemMenuTreeVo】对象
     * @Author：aman
     * @Date：2025/1/17 11:18
     */
    public static SystemMenuTreeVo buildMenuTree(SystemMenuVo systemMenuVo) {
        String component = systemMenuVo.getComponent();
        SystemMenuTreeVo systemMenuTreeVo = new SystemMenuTreeVo();
        systemMenuTreeVo.setName(systemMenuVo.getRouteName());
        systemMenuTreeVo.setPath(systemMenuVo.getPath());
        systemMenuTreeVo.setComponent(component);
        systemMenuTreeVo.setMeta(JSON.to(Meta.class, systemMenuVo.getMeta()));
        systemMenuTreeVo.setChildren(systemMenuVo.getChildren());
        return systemMenuTreeVo;
    }

    /**
     * @Description：用户登陆成功后，获取系统菜单信息
     * @Author：aman
     * @Date：2025/1/17 10:18
     */
    @Override
    public List<SystemMenuTreeVo> getMenuList(List<String> userLoginPermissions) {
        List<SystemMenu> systemMenus;
        if (CollectionUtil.isEmpty(userLoginPermissions)) {
            return new ArrayList<>();
        } else {
            systemMenus = baseMapper.selectList(new LambdaQueryWrapper<SystemMenu>()
                    .notIn(SystemMenu::getMenuType, MenuTypeEnum.BUTTON.getCode())
                    .in(SystemMenu::getPermission, userLoginPermissions));
        }
        List<SystemMenuVo> menuVOS = convertSysResourceToMenuVO(systemMenus);
        return buildSystemMenuTreeVo(menuVOS);
    }

    /**
     * @Description：查询菜单列表
     * @Author：aman
     * @Date：2025/1/17 10:19
     */
    @Override
    public List<SystemMenuListVo> queryMenuList(List<String> permissionCodes) {
        List<SystemMenuListVo> systemMenuVos = convertSysResourceToMenuListVO(getBaseQueryWrapper(permissionCodes));
        Map<String, SystemMenuListVo> map = new HashMap<>();
        // 先将所有资源按照父节点ID进行分组
        for (SystemMenuListVo menuVo : systemMenuVos) {
            menuVo.setChildren(new ArrayList<>());
            // 如果是根节点则直接加入结果列表
            if (menuVo.getParentId() == 0) {
                map.put(String.valueOf(menuVo.getId()), menuVo);
            } else {
                // 如果不是根节点，则加入父节点的 children 列表
                SystemMenuListVo parent = map.get(menuVo.getParentId().toString());
                if (ObjectUtils.isNotEmpty(parent)) {
                    parent.getChildren().add(menuVo);
                } else {
                    systemMenuVos.stream().filter(menu -> menu.getId().equals(menuVo.getParentId())).toList().forEach(menu -> menu.getChildren().add(menuVo));
                }
            }
        }
        return systemMenuVos.stream().filter(menu -> menu.getParentId() == 0).toList();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insertMenu(SystemMenu systemMenu) {
        verifyMenuIsExist(systemMenu);
        baseMapper.insert(systemMenu);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateMenu(SystemMenu systemMenu) {
        List<SystemMenu> systemMenus = baseMapper.selectList(new LambdaQueryWrapper<SystemMenu>()
                .eq(SystemMenu::getTenantId, systemMenu.getTenantId())
                .eq(SystemMenu::getPath, systemMenu.getPath())
                .or()
                .eq(SystemMenu::getRouteName, systemMenu.getRouteName()));
        List<SystemMenu> systemMenuList = systemMenus.stream().filter(item -> !item.getId().equals(systemMenu.getId())).toList();
        if (CollectionUtil.isNotEmpty(systemMenuList)) {
            throw new BizException(INSERT_MENU_ROUTNAME_OR_PATH_REPEAT.getCode(), INSERT_MENU_ROUTNAME_OR_PATH_REPEAT.getReason());
        }
        baseMapper.updateById(systemMenu);
        return true;
    }

    /**
     * @Description：通过id批量更新菜单状态
     * @Author：aman
     * @Date：2025/1/17 09:49
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateMenuStatus(SystemMenuDto dto) {
        if (ObjectUtil.isEmpty(dto) || ObjectUtil.isEmpty(dto.status()) || CollectionUtil.isEmpty(dto.ids())) {
            throw new BizException(ERR_COMMON_PARAMS.getCode(), ERR_COMMON_PARAMS.getReason());
        }
        systemMenuMapper.updateMenuStatusByIds(dto.status(), dto.ids());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteMenuByIds(List<Integer> ids) {
        List<SystemMenu> systemMenus = baseMapper.selectList(new LambdaQueryWrapper<SystemMenu>().in(SystemMenu::getId, ids).or().in(SystemMenu::getParentId, ids));
        if (CollectionUtil.isNotEmpty(systemMenus.stream().filter(menu -> menu.getStatus() == Boolean.TRUE).toList())) {
            throw new BizException(ERROR_MENU_QY_STATUS.getCode(), ERROR_MENU_QY_STATUS.getReason());
        }
        List<Integer> menuIds = systemMenus.stream().map(SystemMenu::getId).toList();
        ids.addAll(menuIds);
        List<Integer> delMenuIds = ids.stream().distinct().toList();
        systemRoleMenuMapper.delete(new LambdaQueryWrapper<SystemRoleMenu>().in(SystemRoleMenu::getMenuId, delMenuIds));
        baseMapper.deleteByIds(delMenuIds, true);
        return true;
    }

    /**
     * @description：校验菜单是否存在
     * @author：aman
     * @date：2025/2/25 16:09
     */
    private void verifyMenuIsExist(SystemMenu systemMenu) {
        Long cont = baseMapper.selectCount(new LambdaQueryWrapper<SystemMenu>()
                .eq(SystemMenu::getTenantId, systemMenu.getTenantId())
                .eq(SystemMenu::getPath, systemMenu.getPath())
                .or()
                .eq(SystemMenu::getRouteName, systemMenu.getRouteName()));
        if (cont > 0) {
            throw new BizException(INSERT_MENU_ROUTNAME_OR_PATH_REPEAT.getCode(), INSERT_MENU_ROUTNAME_OR_PATH_REPEAT.getReason());
        }
    }

    /**
     * @Description：查询所有菜单信息，返回集合数据
     * @Author：aman
     * @Date：2025/1/17 10:21
     */
    private List<SystemMenu> getBaseQueryWrapper(List<String> permissionCodes) {
        LambdaQueryWrapper<SystemMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(CollectionUtil.isNotEmpty(permissionCodes), SystemMenu::getPermission, permissionCodes);
        return list(queryWrapper);
    }
}
